home *** CD-ROM | disk | FTP | other *** search
/ PLAYymate for OS/2 / Playmate for OS2.iso / p4os2035 / biopaint.c < prev    next >
C/C++ Source or Header  |  1989-02-07  |  9KB  |  289 lines

  1. /*  APPPaint() - Parent window WM_PAINT processing routine.
  2. *
  3. *   Created by Microsoft Corp., 1989
  4. *
  5. *   Purpose:
  6. *       Routine to graph biorhythm cycles and tabulate dates.
  7. *
  8. *   Arguments:
  9. *       hWnd          - Handle of Window owning message
  10. *       message       - Message itself
  11. *       mp1           - Extra message-dependent info
  12. *       mp2           - Extra message-dependent info
  13. *
  14. *   Globals (static):
  15. *       Cycle[]       - Array holding period for phy/emot/int: 23,28,33
  16. *       cDayOfWeek[]  - Array of chars holding first letter of days of week.
  17. *       Color[]       - Set of colored pens used to identify cycles.
  18. *
  19. *   Globals (referenced):
  20. *       Born          - Birthdate in julian days.  Read from WIN.INI.
  21. *       SelectDay     - Current day being tracked, day is highlighted.  Is
  22. *                       in units of days from birth date.  Date of present
  23. *                       day initially used in WM_CREATE.
  24. *       Day           - Day number from date born which is top line being
  25. *                       displayed.  Initially three days before SelectDay.
  26. *       bBorn         - Boolean indicating whether valid birtdate entered or
  27. *       rclClient    - Size of client area defined by WM_SIZE message
  28. *       LinesPerPage  - Number of system font lines on client area, defined
  29. *                       by WM_SIZE message handling
  30. *       tmFontInfo    - Text Metric structure defined during WM_CREATE 
  31. *
  32. *   Description:
  33. *       Tabulates dates and graphs cycles.  On color displays, weekends
  34. *       are written in red.  The update rectangle is used to minimize
  35. *       repaint time of affected client area.
  36. *
  37. *   Limits:
  38. *       N/A
  39. */
  40.  
  41. #define INCL_WIN
  42. #define INCL_GPI
  43. #include <os2.h>
  44.  
  45. #include "bio.h"
  46. #include <math.h>
  47. #include <stdio.h>
  48.  
  49. /* Read-only global variables */
  50. extern double   Born;
  51. extern long     Day, SelectDay;
  52. extern BOOL     bBorn;
  53. extern FONTMETRICS tmFontInfo;
  54. extern int      LinesPerPage;
  55. extern RECTL    rclClient;
  56. extern SHORT    cxDateField;
  57.  
  58. /* Read-only static variables */
  59. static double   Cycle[] = { 23.0, 28.0, 33.0 };
  60. static char     cDayOfWeek[] = "MTWTFSS";
  61. extern LONG     Color[];
  62.  
  63. VOID APIENTRY APPPaint( hWnd )
  64. HWND   hWnd;
  65. {
  66.     HPS         hPS;
  67.     POINTL      ptl;
  68.     int         y, i;
  69.     int         start, last;
  70.     char        szDay[16];
  71.     int         Amplitude, offset;
  72.     int         year, month;
  73.     double      day;
  74.     RECTL       rc, rcClip;
  75.     int         DayOfWeek;
  76.     HRGN    hrgnClip;
  77.     POINTL    ptlTextBox[5];
  78.  
  79.     hPS = WinBeginPaint( hWnd, NULL, &rcClip );
  80.  
  81.     /* Erase client area */
  82.     WinQueryWindowRect( hWnd, &rc );
  83.     WinFillRect( hPS, &rc, CLR_WHITE );
  84.  
  85.     /* Label parts of table and graph. */
  86.     ptl.y = rclClient.yTop - tmFontInfo.lMaxBaselineExt + /* Top line */
  87.             tmFontInfo.lMaxDescender;
  88.     ptl.x = 0;
  89.     GpiCharStringAt( hPS, &ptl, 7L, (PCH)"   DATE" );
  90.     ptl.x = cxDateField + tmFontInfo.lAveCharWidth;
  91.     GpiCharStringAt( hPS, &ptl, 3L, (PCH)"LOW" );
  92.     GpiQueryTextBox( hPS, 4L, "HIGH", TXTBOX_COUNT, ptlTextBox );
  93.     ptl.x = rclClient.xRight - ptlTextBox[TXTBOX_CONCAT].x - tmFontInfo.lAveCharWidth;
  94.     GpiCharStringAt( hPS, &ptl, 4L, (PCH)"HIGH" );
  95.  
  96.     /* Underline labels from left to right across client area */
  97.     ptl.y = rclClient.yTop - tmFontInfo.lMaxBaselineExt;
  98.     ptl.x = 0;
  99.     GpiMove( hPS, &ptl );
  100.     ptl.x = rclClient.xRight;
  101.     GpiLine( hPS, &ptl );
  102.  
  103.     /* Draw a vertical line separator between dates and cycles */
  104.     ptl.y = rclClient.yTop;
  105.     ptl.x = cxDateField;
  106.     GpiMove( hPS, &ptl );
  107.     ptl.y = rclClient.yBottom;
  108.     GpiLine( hPS, &ptl );
  109.  
  110.     /* Draw a dotted vertical center line to reference cycles */
  111.     GpiSetLineType( hPS, LINETYPE_DOT );
  112.     ptl.x = (cxDateField + rclClient.xRight) / 2;
  113.     GpiMove( hPS, &ptl );
  114.     ptl.y = rclClient.yTop;
  115.     GpiLine( hPS, &ptl );
  116.     /* (Should not have to restore line type after EndPaint) */
  117.     GpiSetLineType( hPS, LINETYPE_DEFAULT );
  118.  
  119.     /* Update only the range of lines which fall into update rectangle */
  120.     start = (int)((rclClient.yTop - rcClip.yTop) / tmFontInfo.lMaxBaselineExt);
  121.     if (start<1)
  122.        start = 1;
  123.     last = (int)((rclClient.yTop - rcClip.yBottom) / tmFontInfo.lMaxBaselineExt);
  124.     if (last>(LinesPerPage-1))
  125.        last = LinesPerPage-1;
  126.     
  127.     /* Set clip rectangle to completely draw entire rectangle representing
  128.        each date affected.  Start drawing one day before and after
  129.        (outside clip rectangle) so that cycle lines will connect correctly
  130.        with unaffected lines. */
  131.     rcClip.yTop = rclClient.yTop - start*tmFontInfo.lMaxBaselineExt;
  132.     start--;
  133.     last++;
  134.     rcClip.yBottom = rclClient.yTop - last*tmFontInfo.lMaxBaselineExt + 1;
  135.     hrgnClip = GpiCreateRegion( hPS, 1L, &rcClip );
  136.     GpiSetClipRegion( hPS, hrgnClip, &hrgnClip );
  137.  
  138.     /* List days and date */
  139.     for (y=start; y<=last; y++) {
  140.         /* Get the calendar date from julian day */
  141.         calendar( Born+Day+y-1, &year, &month, &day );
  142.         /* Get offset into days of the week initials array */
  143.         DayOfWeek = (int)((LONG)(Born+Day+y) % 7);
  144.         /* Assemble each of the parts in a buffer */
  145.     sprintf(szDay, " %02d-%02d-%02d",
  146.                 month, (int)day, year - (trunc4((double)year / 100)*100) );
  147.         /* If color available, draw weekends in red */
  148.         if (DayOfWeek > 4)
  149.            GpiSetColor( hPS, CLR_RED );
  150.         ptl.x = 0;
  151.         ptl.y = rclClient.yTop - ((y+1)*tmFontInfo.lMaxBaselineExt -
  152.         tmFontInfo.lMaxDescender);
  153.     GpiCharStringAt( hPS, &ptl, 1L, (PCH)&cDayOfWeek[DayOfWeek] );
  154.     GpiQueryWidthTable( hPS, (LONG)'W', 1L, &ptl.x );
  155.     GpiCharStringAt( hPS, &ptl, 9L, (PCH)szDay );
  156.         GpiSetColor( hPS, CLR_BLACK );
  157.     }
  158.  
  159.     /* Amplitude of sin wave is half client area minus space for dates */
  160.     Amplitude = (int)((rclClient.xRight - cxDateField - tmFontInfo.lAveCharWidth) >> 1);
  161.     /* Move to right, make room for column of dates */
  162.     offset = (int)(Amplitude + cxDateField + tmFontInfo.lAveCharWidth - (tmFontInfo.lAveCharWidth>>1));
  163.     for (i=0; i<3 && bBorn; i++ ) {
  164.         GpiSetColor( hPS, Color[i] );
  165.         for (y=start; y<=last; y++) {
  166.             ptl.x = (int)(sin( (y+Day-1)/Cycle[i]*2*3.14159 ) * Amplitude + offset);
  167.             ptl.y = rclClient.yTop - (y*tmFontInfo.lMaxBaselineExt +
  168.                         tmFontInfo.lMaxBaselineExt/2);
  169.             if ((y+Day-1 > 0) && (y>start))
  170.                GpiLine( hPS, &ptl );
  171.             else
  172.                GpiMove( hPS, &ptl );
  173.         }
  174.     }
  175.  
  176.     /* Draw highlight on selected day if visible. */
  177.     if ((SelectDay >= Day) && (SelectDay - Day < LinesPerPage - 1)) {
  178.         rc.xRight = rclClient.xRight;
  179.         rc.xLeft = rclClient.xLeft;
  180.         rc.yTop = rclClient.yTop - (int)(SelectDay - Day + 1) * tmFontInfo.lMaxBaselineExt;
  181.         rc.yBottom = rc.yTop - tmFontInfo.lMaxBaselineExt + 1;
  182.         WinInvertRect( hPS, &rc );
  183.     }
  184.  
  185.     WinEndPaint( hPS );
  186.  
  187.     return;
  188. }
  189.  
  190.  
  191. /*  julian() - Compute julian date from Gregorian calendar date.
  192. *
  193. *   Purpose:
  194. *       Provide a standard time base.
  195. *
  196. *   Arguments:
  197. *       year          - Calendar year
  198. *       month         - Calendar month
  199. *       day           - Calendar day and fraction
  200. *
  201. *   Return Value:
  202. *       double        - Julian date converted
  203. *
  204. *   Description:
  205. *       Convert Gregorian dates to Julian Days.  Refer to Alamanac for
  206. *       Computers (1978), p. B2, Naval Observatory Pub.
  207. *
  208. *   Limits:
  209. *       Valid between ~1900 and 2099.
  210. *
  211. */
  212.  
  213. double PASCAL julian (year, month, day)
  214. int    year, month;
  215. double day;
  216. {
  217.   double dj;
  218.   double fracDay, intDay;
  219.  
  220.   fracDay = modf(day, &intDay);
  221.   dj = (long)367*year - 7*(year + (month+9) / 12) / 4 + 275*month / 9 +
  222.        intDay + 1721013.5 + fracDay;
  223.   return dj;
  224. }
  225.  
  226.  
  227. /*  calendar() - Compute Gregorian calendar date from julian date.
  228. *
  229. *   Purpose:
  230. *       Provide a standard time base.
  231. *
  232. *   Arguments:
  233. *       juldate       - Julian date to convert
  234. *       year          - Calendar year result
  235. *       month         - Calendar month result
  236. *       day           - Calendar day and fraction result
  237. *
  238. *   Return Value:
  239. *       void
  240. *
  241. *   Globals (modified):
  242. *       none
  243. *
  244. *   Globals (referenced):
  245. *       none
  246. *
  247. *   Description:
  248. *       Convert Julian Days to Gregorian date.  Refer to Astronomical
  249. *       Formulae for Calculators (1979), p. 23, by Jean Meeus.
  250. *
  251. *   Limits:
  252. *       Valid for positive Julian Day values.
  253. *
  254. */
  255.  
  256. void PASCAL calendar (juldate, year, month, day)
  257. double juldate;
  258. int *year;
  259. int *month;
  260. double *day;
  261. {
  262.   long b, c, d, e, z, alf;
  263.  
  264.   juldate = juldate + 0.5;
  265.   z = trunc4(juldate);
  266.   alf = trunc4((z - 1867216.25)/36524.25);
  267.   b = z + 1 + alf - alf / 4 + 1524;
  268.   c = trunc4((b - 122.1)/365.25);
  269.   d = 365*c + c / 4;
  270.   e = trunc4((b - d)/30.6001);
  271.   *day = b - d - trunc4(30.6001*e) + juldate - z;
  272.   if (e > 13)
  273.       *month = (int)e - 13;
  274.   else
  275.       *month = (int)e - 1;
  276.   if (*month > 2)
  277.       *year = (int)c - 4716;
  278.   else
  279.       *year = (int)c - 4715;
  280. }
  281.  
  282. long PASCAL trunc4( dflValue )
  283. double dflValue;
  284. {
  285.    double intValue;
  286.    modf(dflValue, &intValue);
  287.    return (long)intValue;
  288. }
  289.